﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using UnitSoftware.WinformExtentions;
using System.Data.Linq;

namespace UnitSoftware.LINQ2SQLExtentions
{
    public partial class EntityBoundControl : UserControl
    {
        object _entityManager;
        object _entity;

        public event EventHandler OnSave;
        public event EventHandler OnCancel;

        public EntityBoundControl()
        {
            InitializeComponent();
        }

        public void Initialise<TEntity, TDataContext>(EntityManager<TEntity, TDataContext> tableWrapper, TEntity entity) where TEntity : class where TDataContext : DataContext
        {
            _entityManager = tableWrapper;
            _entity = entity;
            InitialiseElements(entity);

            foreach (Control control in this.Controls)
                if (control is IBoundEditControl)
                    ((IBoundEditControl)control).ValueChanged += EntityBoundControl_ValueChanged;

            SetButtonState();
        }

        void EntityBoundControl_ValueChanged(object sender, EventArgs e)
        {
            SetButtonState();
        }

        private void SetButtonState()
        {
            _saveChangesButton.Enabled = _cancelChangesButton.Enabled = HasChanges();
        }

        protected virtual void InitialiseElements(object entity) { }

        private void RestoreOriginalEntityValues()
        {
            foreach (Control control in this.Controls)
                if (control is IBoundEditControl)
                    ((IBoundEditControl)control).RestoreOriginalValue();
        }

        protected void Reset()
        {
            RestoreOriginalEntityValues();
            InitialiseElements(_entity);
        }

        protected void Cancel()
        {
            RestoreOriginalEntityValues();

            if (OnCancel != null)
                OnCancel(this, EventArgs.Empty);
        }

        protected void Save<TEntity, TDataContext>() where TEntity : class where TDataContext : DataContext
        {
            ((EntityManager<TEntity, TDataContext>)_entityManager).Persist((TEntity)_entity);

            InitialiseElements(_entity);

            if (OnSave != null)
                OnSave(this, EventArgs.Empty);
        }

        protected List<PropertyChangeDetails> ChangeDetails
        {
            get
            {
                return GetChangeDetails(false);
            }
        }

        private List<PropertyChangeDetails> GetChangeDetails(bool returnOnFirstChange)
        {
            List<PropertyChangeDetails> changes = new List<PropertyChangeDetails>();
            foreach (Control control in this.Controls)
                if (control is IBoundEditControl)
                {
                    IBoundEditControl boundcontrol = ((IBoundEditControl)control);

                    if (!(boundcontrol.NewValueString == boundcontrol.OriginalValueString))
                    {
                        changes.Add(
                            new PropertyChangeDetails(
                                boundcontrol.PropertyName,
                                boundcontrol.OriginalValueString,
                                boundcontrol.NewValueString));

                        if (returnOnFirstChange)
                            return changes;
                    }
                }

            return changes;
        }

        public bool HasChanges
        {
            get
            {
                return (GetChangeDetails(true).Count > 0);
            }
        }
    }

    public struct PropertyChangeDetails
    {
        readonly string _propertyName;
        readonly string _originalValue;
        readonly string _newValue;

        public PropertyChangeDetails(string propertyName, string originalValue, string newValue)
        {
            _propertyName = propertyName;
            _originalValue = originalValue;
            _newValue = newValue;
        }
    }
}
